分类
联系方式
  1. 新浪微博
  2. E-mail

Dart eval:exportGraph 概念

介绍

Compiler.dart 的 _resolveImportsAndExports 负责对 Library 的导入导出关系进行分析,其中包含一个 exportGraph,本文梳理 exportGraph 的逻辑。

在 Compiler.dart 的 _resolveImportsAndExports 中,exportGraph 创建方式如下:

final exportGraph = DirectedGraph<Uri>({
  for (final l in libraries)
    l.uri: {
      for (final export in l.exports) Uri.parse(export.uri.stringValue!)
    }
});

实例

找到一个与 export 相关的测试用例:'Export chains',位于 test\lib_composition_test.dart。

该用例中声明了如下源码:

main.dart:

import 'package:example/b1.dart';
int main() {
  final b = ClassB();
  return b.number();
}

b1.dart:

library b1;
export 'package:example/b2.dart' show ClassB;

b2.dart:

export 'package:example/b3.dart';

b3.dart:

class ClassB {
  ClassB();
  int number() { return 8; }
}

他们之间的相互关系如下:

  • main.dart 文件中:
    • 通过 import 关键字将 b1.dart 引入
    • 并调用了 b1.dart 中导出的 ClassB 类
  • b1.dart 文件中:
    • 通过 export 关键字将 b2.dart 中的 ClassB 类导出,供其他文件调用
  • b2.dart 文件中:
    • 通过 export 关键字将 b3.dart 中的内容导出
  • b3.dart 文件中:
    • 定义了一个 ClassB 类
    • 包含一个构造函数和一个返回整型数的 number() 方法

exportGraph 运行时效果

运行时看 exportGraph 的 _edges 属性,包含 7 个元素,伪代码如下:

{
    "dart:core": {},
    "dart:math": {},
    "dart:async": {},
    "package:example/main.dart": {},
    "package:example/b1.dart": {
        "package:example/b2.dart"
    },
    "package:example/b2": {
        "package:example/b3.dart"
    },
    "package:example/b3.dart": {}
}

与代码对比,终于理解了 exportGraph 就是每个文件对外的 export,并且是能够串起来的(图)。

exportGraph.crawler.tree

继续来到下面逻辑:

for (final import in [
  ...l.imports.map((e) => _Import(
      Uri.parse(e.uri.stringValue!), e.prefix?.name, e.combinators)),
  if (!isDartCore) _Import(dartCoreUri, null)
]) {
  final tree = exportGraph.crawler.tree(import.uri);
  
  final importedLibs = [...tree.expand((e) => e), import.uri]
    .map((e) =>
        uriMap[e] ??
        (throw CompileError(
            "Cannot find import '$e' (while parsing '${l.uri}')")))
    .toSet();
  
  final importedExports =
    importedLibs.map((e) => e.exports).expand((e) => e);

注意,这部分代码套在 for (final l in libraries) { 内,当 l 为 main.dart 时: tree 为,列表:

[
    {"package:example/b2.dart"},
    {"package:example/b2.dart", "package:example/b3.dart"}
]

即以 main.dart 作为根的引用关系链。 importedLibs 为,集合:

{
    Library("package:example/b2.dart"),
    Library("package:example/b3.dart"),
    Library("package:example/b1.dart"),
}

把 main 中的 import(b1)也加上了。

importedExports 为类型为 ExportDirective 的 Iterator,把 importedLibs 中所有的 export 都展开了。

exportsPerUri 为 <Uri, List<ExportDirective>>{}

{
    "package:example/b3.dart": [
        ExportDirectiveImpl (export 'package:example/b3.dart')
    ],
    "package:example/b2.dart": [
        ExportDirectiveImpl (export 'package:example/b2.dart' show ClassB;)
    ]
}

visibleDeclarations:

mappedVisibleDeclarations:

result,Map:

{
    Library("dart:core"): {
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("dart:math"): {
        "Point": DeclarationOrPrefix,
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("dart:async"): {
        "Completer": DeclarationOrPrefix,
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("package:example/main.dart"): {
        "main": DeclarationOrPrefix,
        "ClassB": DeclarationOrPrefix,
        "ClassB.": DeclarationOrPrefix,
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("package:example/b1.dart"): {
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("package:example/b2.dart"): {
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
    Library("package:example/b3.dart"): {
        "ClassB": DeclarationOrPrefix,
        "ClassB.": DeclarationOrPrefix,
        "print": DeclarationOrPrefix,
        "Future": DeclarationOrPrefix,
        "Duration": DeclarationOrPrefix,
        "DateTime": DeclarationOrPrefix,
    },
}